package ece496.sensorService;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Locale;
import java.util.Random;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.text.format.Time;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import android.media.AudioManager;
import android.media.SoundPool;
import android.media.SoundPool.OnLoadCompleteListener;

public class SensorServiceActivity extends Activity implements OnInitListener {
    // Buttons and textview and stuff
	private static final int MY_DATA_CHECK_CODE = 101;
	private TextToSpeech tts;
	
    Button startButton;
    Button stopButton;
    Button invokeButton;
    TextView data;
    EditText editField;
    
    long delayL = 0;
    long delayR = 0;
    int test_int = 0;
    int lastTTSmsg = -1; //the last TTSmsg that was played
    float oldDistance = 10;
    
    Random test_random = new Random();
    boolean serviceStarted = false;
    boolean keepRunning = false;
    private ISensorRemoteService sensorService;
    private SensorServiceConnection conn = null;
    
    private Task displayTask = new Task();
    private Handler displayHandler;
    
    String TAG = "dataLogger";
    //start TTS

    //sound
    int soundID = 0;
    int soundID1 = 0;
    int soundID3 = 0;
    private SoundPool soundPool;
    boolean sndLoaded = false;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        this.setVolumeControlStream(AudioManager.STREAM_MUSIC);
        soundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 0);
        //Probably don't need this here
        soundPool.setOnLoadCompleteListener(new OnLoadCompleteListener() {

            public void onLoadComplete(SoundPool soundPool, int sampleId,
                    int status) {
                sndLoaded = true;
            }
        });
        soundID = soundPool.load(this, R.raw.sound1, 1);
        soundID1 = soundPool.load(this,R.raw.sound2,1);
        data = (TextView) findViewById(R.id.data);
        
        //SPEECH!!
        tts = new TextToSpeech(this,this);
        
        // Link Button
        startButton = (Button) findViewById(R.id.startButton);
        stopButton = (Button) findViewById(R.id.stopButton);
        invokeButton = (Button) findViewById(R.id.invokeButton);

        startButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                startService();
            }
        });

        stopButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                keepRunning = false;
                try {
                    sensorService.stopThread();
                } catch (RemoteException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                stopService();
            }
        });

        // Link Edit field
        editField = (EditText) findViewById(R.id.editText1);

        invokeButton.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                keepRunning = !keepRunning;
                writeToCard(editField.getText().toString());
            }
        });

        displayHandler = new Handler();
        displayHandler.postDelayed(displayTask, 0);
    }

    class Task implements Runnable {

        public void run() {
            if (keepRunning) {
                invokeService();
            }
            displayHandler.postDelayed(this, 0);
        }
    }
    
    private void startService() {
        // Start Service
        if (serviceStarted) {
            Toast.makeText(SensorServiceActivity.this, "Service already started", Toast.LENGTH_SHORT).show();
        } else {
            Intent iServiceIntent = new Intent();
            iServiceIntent.setClassName("ece496.sensorService", "ece496.sensorService.SensorService");
            startService(iServiceIntent);
            serviceStarted = true;
            updateServiceStatus();
            Log.d(getClass().getSimpleName(), "startService()");
        }

        // Bind Service
        if (conn == null) {
            conn = new SensorServiceConnection();
            Intent iServiceIntent = new Intent();
            iServiceIntent.setClassName("ece496.sensorService", "ece496.sensorService.SensorService");
            bindService(iServiceIntent, conn, Context.BIND_AUTO_CREATE);
            updateServiceStatus();
            Log.d(getClass().getSimpleName(), "bindService()");
        } else {
            Toast.makeText(SensorServiceActivity.this, "Cannot bind - service already bound", Toast.LENGTH_SHORT).show();
        }
    }

    private void stopService() {
        // Unbind Service

        if (conn != null) {
            unbindService(conn);
            conn = null;
            updateServiceStatus();
            Log.d(getClass().getSimpleName(), "releaseService()");
        } else {
            Toast.makeText(SensorServiceActivity.this, "Cannot unbind - service not bound", Toast.LENGTH_SHORT).show();
        }

        // Stop Service
        if (!serviceStarted) {
            Toast.makeText(SensorServiceActivity.this, "Service not yet started", Toast.LENGTH_SHORT).show();
        } else {
            Intent iServiceIntent = new Intent();
            iServiceIntent.setClassName("ece496.sensorService", "ece496.sensorService.SensorService");
            stopService(iServiceIntent);
            serviceStarted = false;
            updateServiceStatus();
            Log.d(getClass().getSimpleName(), "stopService()");
        }
    }

    private void invokeService() {
        if (conn == null) {
            Toast.makeText(SensorServiceActivity.this, "Cannot invoke - service not bound", Toast.LENGTH_SHORT).show();
        } else {
            try {
                //float value = ;
            	String[] res = sensorService.returnSt().split(" ");
            	String bat = Double.toString(sensorService.return_mon());
            	
                setData(sensorService.returnSt() + "\nBattery level: " + bat + "%");
                if (res.length < 3) 
                	{setData("No Data");
                	return ;
                	
                	}
                float left = Float.parseFloat( res[0]);
                float centre = Float.parseFloat(res[1]);
                float right = Float.parseFloat(res[2]);
                
                //find the shortest distance
                int flag = 0;
                float distance = -1;
                if (left > 0){distance = left;flag = 1;}
                if (centre > 0)
                { flag +=2;
                	if (distance > centre) distance = centre; 
                }
                if (right > 0)
                {flag +=4;
                if (distance > right && right > 0) distance = right;
                }
                
                //Obtain numbers from sensorService.returnSt()
                //check if it's a large or small obstacle
                //based on the numbers
                //writeToCard("\nflag = " + flag + "distance = " + distance);
                alertUser(left,centre,right,flag);
                Log.d(getClass().getSimpleName(), "invokeService()");
            } catch (RemoteException re) {
                Log.e(getClass().getSimpleName(), "RemoteException");
            }
        }
    }
    
    long delayTTS = 0;
    boolean aheadFlag = true;
    boolean closeFlag = true;
    boolean clearFlag = true;
    private void alertUser(float left, float centre, float right, int direction)
    {
    	int threshold = 3;
    	//check if the obstacle is close enough
    	//now check when was the last time a message was sent
    	//if it was a while ago, speak
    	//otherwise, beep
    	
    	//direction
    	//000
    	//001
    	//010
    	//011
    	//100
    	//101
    	//110
    	//111
    	int delaySecond = 0;
    	int play = -1;
    	int soundPlay = 1;
    	boolean leftSound = ((direction & 1) == 1);
    	boolean rightSound = ((direction & 4) == 4);
    	float distance = -1;
    	
    	//Log.i("alertUser", "leftSound: "+leftSound+" and rightSound: "+rightSound+"\n");
    	String msg="";
    	
    	switch (direction)
    	{	//obstacle on left
    		case 1:
    			//check the last message
    			//msg = "Obstacle on the right";
    			play = 1;// soundPlay = 1;
    			distance = right;
    			break;
    		case 2: // ahead
    			msg = "Ahead";
    			play = 2; soundPlay = -1;
    			distance = centre;
    			break;
    		case 3: // left and ahead
    			msg = "Ahead";
    			play = 3;// soundPlay = 1;
    			distance = Math.min(right,centre);
    			break;
    		case 4: //right
    			//msg = "Obstacle on the left";
    			play = 4;// soundPlay = 1;
    			distance = left;
    			break;
    		case 5: //left and right
    			//msg = "Obstacle on the sides";
    			play = 5;// soundPlay = 1;
    			distance = Math.min(left,right);
    			break;
    		case 6: // right and ahead
    			msg = "Ahead";
    			play = 6;// soundPlay = 1;
    			distance = Math.min(left, centre);
    			break;
    		case 7: // left/right/ahead
    			msg = "Ahead";
    			play = 7;// soundPlay = 1;
    			distance = Math.min(left, right);
    			break;
    	}
        
    	if (centre < 0.5 && centre > 0) {
    		msg = "Close ahead";
    	}
    	
    	long current = System.currentTimeMillis();
        
        if (centre < 0) {
        	oldDistance = 10;
        	aheadFlag = true;
        	closeFlag = true;
        }
        else
        	clearFlag = true;
        
        if (centre <= 1.0 && centre > 0 && closeFlag) {
        	if (!aheadFlag) { msg = ""; }
        	tts.speak("Stop!", TextToSpeech.QUEUE_FLUSH, null);
        	closeFlag = false;
        }
        else if (oldDistance > 0 && centre < 0 && clearFlag) {
        	tts.speak("Clear", TextToSpeech.QUEUE_FLUSH, null);
        	clearFlag = false;
        }
        else if (((play != lastTTSmsg && play > -1) || (Math.abs(oldDistance-centre) > 0.5)) && !msg.equals(""))
        {
        	writeToCard("\nPlaying msg " + msg);
        	if (!aheadFlag) { msg = ""; }
        	// if obstacle got closer then remove ahead
        	if (centre <= 1) tts.speak("Stop", TextToSpeech.QUEUE_FLUSH, null);
        	else {tts.speak(msg+centre+"metres", TextToSpeech.QUEUE_ADD, null);}tts.speak(msg + centre + "metres", TextToSpeech.QUEUE_FLUSH, null);
        	oldDistance = centre;
        	//tts.speak("at " + distance + "metres", TextToSpeech.QUEUE_ADD,null);
        	//tts.talk(msg);
        	//if the message we are saying now is different from the previous one
        	//set a short delay and play the sound
        	delayTTS = System.currentTimeMillis()+3000;
        	aheadFlag = false;
        	closeFlag = true;
        }
        else if (Math.abs(oldDistance-centre) < 0.5 && current > delayTTS) {
        	if (!aheadFlag) { msg = ""; }
        	if (centre <= 1) tts.speak("Stop", TextToSpeech.QUEUE_FLUSH, null);
        	else {tts.speak(msg+centre+"metres", TextToSpeech.QUEUE_ADD, null);}
        	delayTTS = System.currentTimeMillis()+3000;
        }
        oldDistance = centre;
        
        /*else if (left < 0.7 && right < 0.7 && (left-right) > 0.3 && left > 0 && right > 0) {
    		tts.speak("turn left slightly", TextToSpeech.QUEUE_ADD, null);
    	}
    	else if (left < 0.7 && right < 0.7 && (right-left) > 0.3 && left > 0 && right > 0) {
    		tts.speak("turn right slightly", TextToSpeech.QUEUE_ADD, null);
    	}*/
    	
        lastTTSmsg = play;
        
        if (soundPlay > 0 && (leftSound || rightSound))
        {
        	
        	//play sound here
        	//play audio files and reset current based on distance
            AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
            ;
            float maxVolume = (float) audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
            float actualVolume = (float) audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
            float volumeL = (float) (leftSound ? (0.8 - (centre/3 - 0.3)) * actualVolume/maxVolume: 0);
        	float volumeR = (float) (rightSound ? (0.8 - (centre / 3 - 0.2)) * actualVolume/maxVolume : 0);
        	//int playSound = 0;
        	
        	
        	if (leftSound && current > delayL)
        		{	delaySecond = (int) (left * 3000); 
        		delayL = System.currentTimeMillis() + delaySecond;
        		//	tts.speak("Ah", TextToSpeech.QUEUE_FLUSH, null);
        		soundPool.play(soundID, volumeL, volumeR, 1, 0, 1f);
        		}
             if (rightSound && current > delayR)
            	 {//tts.speak("Oh", TextToSpeech.QUEUE_FLUSH, null);
            	 delaySecond = (int) (right * 3000); 
            	 soundPool.play(soundID1, volumeL, volumeR, 1, 0, 1f);
            	 	delayR = System.currentTimeMillis() + delaySecond;
            	 }
        }
    }
    
    /*private void playSound(int flat, long playTime)
    {
    	if (System.currentTimeMillis() > playTime)
    	{
    		AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
            float actualVolume = (float) audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
            float maxVolume = (float) audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
            float volumeL = actualVolume / maxVolume;
        	float volumeR = actualVolume / maxVolume;
        	
            soundPool.play(0, volumeL, volumeR, 1, 0, 1f);
        	
        	//delaySecond = (int) (distance * 2000);
        	Toast.makeText(SensorServiceActivity.this, Integer.toString(delaySecond), Toast.LENGTH_SHORT).show();
        	delay = System.currentTimeMillis();
            //delay+= delaySecond;
    	}
    }*/
    
    protected void onDestroy() {
        super.onDestroy();
    	tts.shutdown();
    	try {
			sensorService.stopThread();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        displayHandler.removeCallbacks(displayTask);
        displayHandler = null;
        stopService();
    }

    private void updateServiceStatus() {
        String bindStatus = conn == null ? "unbound" : "bound";
        String startStatus = serviceStarted ? "started" : "not started";
        String statusText = "Service status: "
                + bindStatus
                + ","
                + startStatus;
        TextView t = (TextView) findViewById(R.id.Status);
        t.setText(statusText);
    }

    public void writeToCard (String data) {
    try {
    File root = Environment.getExternalStorageDirectory();
    if (root.canWrite()){
    File dataFile = new File(root, "sensor_data.txt");
    FileWriter dataWriter = new FileWriter(dataFile, true);
    dataWriter.append(data + "\n");
    dataWriter.close();
    }
    else {
    setData("cannot write to sdcard\n");
    }
    } catch (IOException e) {
    Log.e(TAG, "Could not write to file " + e.getMessage());
    }
    }
    public void setData(final String string) {
        runOnUiThread(new Runnable() {

            public void run() {
                data.setText(string);
                writeToCard(string);
            }
        });
    }

    class SensorServiceConnection implements ServiceConnection {

        public void onServiceConnected(ComponentName className,
                IBinder boundService) {
            sensorService = ISensorRemoteService.Stub.asInterface((IBinder) boundService);
            Log.d(getClass().getSimpleName(), "onServiceConnected()");
        }

        public void onServiceDisconnected(ComponentName className) {
            sensorService = null;
            updateServiceStatus();
            Log.d(getClass().getSimpleName(), "onServiceDisconnected");
        }
    }

	public void onInit(int status) {
		// TODO Auto-generated method stub
		Intent ttsIntent = new Intent();
		ttsIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
		startActivityForResult(ttsIntent, MY_DATA_CHECK_CODE);
		if (status == TextToSpeech.SUCCESS) {
			tts.setLanguage(Locale.US);
		}
		else if (status == TextToSpeech.ERROR) {
     
		}
	};
}